#include "codec.h"
#include <sys/types.h>
#include <muduo/base/Logging.h>
#include <muduo/base/Mutex.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpServer.h>

#include <boost/bind.hpp>

#include <set>
#include <stdio.h>


class ChatServer : boost::noncopyable {
public:

//首先,在构造函数里注册回调：
    ChatServer(muduo::net::EventLoop *loop,
               const muduo::net::InetAddress &listenAddr)
            : server_(loop, listenAddr, "ChatServer"),
              codec_(boost::bind(&ChatServer::onStringMessage, this, _1, _2, _3))    //向codec_注册onStringMessage()
    {
        server_.setConnectionCallback(
                boost::bind(&ChatServer::onConnection, this, _1));
        server_.setMessageCallback(
                boost::bind(&LengthHeaderCodec::onMessage, &codec_, _1, _2, _3));
    }

    void setThreadNum(int numThreads) {
        server_.setThreadNum(numThreads);
    }

    void start() {
        server_.start();
    }

private:

//以下是处理连接的建立和断开的代码，它把新建的连接加入到connections_容器中，把已断开的连接从容器中删除。
    void onConnection(const muduo::net::TcpConnectionPtr &conn) {
        LOG_INFO << conn->localAddress().toIpPort() << " -> "
                 << conn->peerAddress().toIpPort() << " is "
                 << (conn->connected() ? "UP" : "DOWN");

        muduo::MutexLockGuard lock(mutex_);
        if (conn->connected()) {
            connections_.insert(conn);    //添加
        } else {
            connections_.erase(conn);    //删除
        }
    }

//以下是服务端处理消息的代码
    void onStringMessage(const muduo::net::TcpConnectionPtr &, const std::string &message, muduo::Timestamp) {
        muduo::MutexLockGuard lock(mutex_);
//遍历整个connections_容器
        for (ConnectionList::iterator it = connections_.begin(); it != connections_.end(); ++it) {
            codec_.send(get_pointer(*it), message);    //把消息发送给各个客户连接
        }
    }

//数据成员：
    typedef std::set<muduo::net::TcpConnectionPtr> ConnectionList;
    muduo::net::TcpServer server_;
    LengthHeaderCodec codec_;
    muduo::MutexLock mutex_;
    ConnectionList connections_;
};

int main(int argc, char *argv[]) {
    LOG_INFO << "pid = " << getpid();
    if (argc > 1) {
        muduo::net::EventLoop loop;
        uint16_t port = static_cast<uint16_t>(atoi(argv[1]));
        muduo::net::InetAddress serverAddr(port);        //初始化sockaddr_in
        ChatServer server(&loop, serverAddr);    //初始化聊天服务器
        if (argc > 2) {
            server.setThreadNum(atoi(argv[2]));    //设置多线程
        }
        server.start();
        loop.loop();
    } else {
        printf("Usage: %s port [thread_num]\n", argv[0]);
    }
}